package com.kcht.rd30.service.impl;

import com.kcht.rd30.dto.TimeType;
import com.kcht.rd30.entity.TimeCalibrationEntity;
import com.kcht.rd30.mapper.ITimeCalibrationMapper;
import lombok.extern.slf4j.Slf4j;
import org.zeromq.SocketType;
import org.zeromq.ZContext;
import org.zeromq.ZMQ;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.temporal.TemporalAccessor;

@Slf4j
public class TimeCalibrationHandler implements Runnable {
    private final int port = 10006;
    private String ip;
    private ITimeCalibrationMapper timeCalibrationMapper;
    private Boolean isClose = false;

    public TimeCalibrationHandler(String ip, ITimeCalibrationMapper timeCalibrationMapper) {
        this.ip = ip;
        this.timeCalibrationMapper = timeCalibrationMapper;
        new Thread(this).start();
        log.info("{} ---> 开启校准时间线程",ip);
    }

    @Override
    public void run() {
        while (!isClose) {
            TimeCalibrationEntity tc=null;
            try {
                tc = this.timeCalibrationMapper.findByIp(this.ip);
                if (tc == null) return;
                if (tc.getIsCali()) {
                    configTime(tc);
                }else{
                    log.info("{} ---> 已关闭校准时间服务",ip);
                }
            } catch (Exception e) {
                log.error("未知异常",e);
            }
            try {
                assert tc != null;
                Thread.sleep(tc.getDuration()*1000);
            } catch (InterruptedException e) {
                log.error("sleep中止异常",e);
            }
        }
        log.info("{} ---> 已关闭校准时间线程",ip);
    }

    private void configTime(TimeCalibrationEntity tc) {
        int recvTimeout = 5000;
        try (ZContext context = new ZContext()) {
            try (ZMQ.Socket req = context.createSocket(SocketType.REQ)) {
                req.setLinger(0);
                req.setHeartbeatTimeout(recvTimeout);
                req.setReceiveTimeOut(recvTimeout);
                req.setSendTimeOut(recvTimeout);
                req.connect("tcp://" + ip + ":" + port);
                pub_msg.Pub.pub_request request = pub_msg.Pub.pub_request.getDefaultInstance();
                LocalDateTime now = null;
                if(tc.getTimeType()== TimeType.GMT){
                    now=LocalDateTime.now(ZoneId.of("+0"));
                }else if(tc.getTimeType()==TimeType.BJ){
                    now=LocalDateTime.now(ZoneId.of("+8"));
                }else{
                    now=LocalDateTime.now(ZoneId.of("+0"));
                }
                request = request.toBuilder()
                        .setType(pub_msg.Pub.pub_request.HeadType.setSystemTime)
                        .setSysTime(pub_msg.Pub.SysTimePara.getDefaultInstance().toBuilder()
                                .setSecond(now.getSecond())
                                .setMinute(now.getMinute())
                                .setHour(now.getHour())
                                .setMday(now.getDayOfMonth())
                                .setMonth(now.getMonthValue())
                                .setYear(now.getYear())).build();
                req.send(request.toByteArray());
                final byte[] recv = req.recv();
                if (recv != null && pub_msg.Pub.pub_response.parseFrom(recv).getStatus() == 0) {
                    Instant instant = now.toInstant(ZoneOffset.of("+0"));
                    now = LocalDateTime.ofInstant(instant, ZoneId.of("+8"));
                    log.info(ip + "已校对时间 ---> " + now);
                    tc.setLastCalibrationTime(now);
                    timeCalibrationMapper.updateById(tc);
                } else {
                    log.error(ip + "未能正确校对时间 ---> " + now);
                }
            }
        } catch (Throwable e) {
            log.error("ZMQ未知异常",e);
        }
    }

    public void closeThread() {
        this.isClose = true;
    }
}
